package logic;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;

import utils.Constants;
import utils.FileManager;

public class InformationsExtractor {
	private FileManager fileManager;

	public void printMetricCost(TreeMap<String, TreeMap<String, Integer>> all) {
		Set<String> keys = all.keySet();
		for (String key : keys) {
			Set<String> keys2 = all.get(key).keySet();
			System.out.println();
			System.out.println(" ====== Start NMTR Metric for: " + key
					+ " ====== ");
			System.out.println();
			for (String key1 : keys2) {
				System.out.println(key1 + " = " + all.get(key).get(key1));
			}
			System.out.println();
			System.out.println(" ====== Finished NMTR Metric for: " + key
					+ " ====== ");
			System.out.println();
		}

	}

	public void printCompareMetric(TreeMap<String, TreeMap<String, Integer>> all) {
		Set<String> keys = all.keySet();
		String firstKey = all.firstKey();
		Set<String> keysFirst = all.get(firstKey).keySet();
		System.out.println("Compare NMTR Metric for :" + keys.toString());
		for (String key : keysFirst) {
			System.out.println();
			for (String key1 : keys) {
				Set<String> keys2 = all.get(key1).keySet();
				if (keys2.contains(key)) {
					System.out.println(key1 + " : " + key + " = "
							+ all.get(key1).get(key));
				}
			}
			System.out.println();
		}

	}

	private int getCostNMTR(String line) {
		if (!line.contains(Constants.NAME) || line.contains(Constants.TRASH)) {
			return 0;
		}
		String referencesName = getTransformationRuleName(line);
		String context = getContext(line);
		int cost = 0;
		cost = countPoints(referencesName);
		if ((context.equalsIgnoreCase(Constants.FUNCTIONCALL))
				&& referencesName.contains(Constants.SELF)) {
			cost--;
		} else if (referencesName.contains("_get")
				|| referencesName.contains("get")) {
			cost--;
		} else if (!referencesName.contains(Constants.SELF)) {
			cost = 0;
		}
		return cost;

	}

	private int getCostNMTR(String line, String var) {
		if (!line.contains(Constants.NAME) || line.contains(Constants.SELF)) {
			return 0;
		}
		String referencesName = getTransformationRuleName(line);
		String context = getContext(line);
		int cost = 0;
		cost = countPoints(referencesName) + 2;
		if ((context.equalsIgnoreCase(Constants.FUNCTIONCALL))) {
			cost -= 1;
		}
		if (!referencesName.contains(var + ".")
				|| context.equalsIgnoreCase(Constants.TRASH)) {
			cost = 0;
		}
		return cost;

	}

	private int countPoints(String line) {
		int cost = 0;
		for (char c : line.toCharArray()) {
			if (c == '.') {
				cost++;
			}
		}

		return cost;
	}

	private boolean contains(List<String> list, String word) {
		for (String name : list) {
			if (name.equalsIgnoreCase(word)) {
				return true;
			}
		}
		return false;
	}

	public TreeMap<String, Integer> sumTransformationCost(
			TreeMap<String, TreeMap<String, Integer>> all) {
		TreeMap<String, Integer> tt = new TreeMap<String, Integer>();
		Set<String> keys = all.keySet();
		for (String key : keys) {
			int cost = 0;
			Set<String> keys2 = all.get(key).keySet();
			for (String key1 : keys2) {
				cost += all.get(key).get(key1);
			}
			tt.put(key, cost);
			cost = 0;
		}

		return tt;

	}

	public InformationsExtractor() {
		this.fileManager = new FileManager();

	}

	public List<List<String>> getTransformationsList(String path) {
		File[] files = getTransformations(path);
		List<List<String>> transformations = new LinkedList<List<String>>();
		for (File transformationFile : files) {
			try {
				transformations.add(this.fileManager
						.readTransformation(transformationFile));
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return transformations;
	}

	private TreeMap<String, Integer> getStatementsTreeMap() {
		TreeMap<String, Integer> costElements = new TreeMap<String, Integer>();
		costElements.put(Constants.ELSE_BRANCH, 0);
		costElements.put(Constants.IFSTATEMENT, 0);
		costElements.put(Constants.ITERATOR_STATEMENT, 0);
		costElements.put(Constants.RESULT_ASSIGNMENT, 0);
		costElements.put(Constants.VARIABLE_DECLARATION_STATEMENT, 0);
		costElements.put(Constants.WHILE_STATEMENT, 0);
		return costElements;
	}

	public TreeMap<String, TreeMap<String, Integer>> getMetricCost(
			List<List<String>> transformations, int typeMetric) {
		TreeMap<String, TreeMap<String, Integer>> allInformations = new TreeMap<String, TreeMap<String, Integer>>();
		for (List<String> transformation : transformations) {
			String transformationName = getTransformationName(transformation);
			TreeMap<String, Integer> ruleMap = new TreeMap<String, Integer>();
			String transformationRuleName = null;
			String contextName = null;
			int cost = 0;
			String var = Constants.DEFAULT;
			boolean isVar = false;
			for (String line : transformation) {
				if (line.startsWith(Constants.OPEN_TAG
						+ Constants.TRANSFORMATION_RULE)) {
					transformationRuleName = getTransformationRuleName(line);
				} else if (line.startsWith(Constants.OPEN_TAG
						+ Constants.CONTEXT)) {
					contextName = getContext(line);
					if (typeMetric == Constants.NMTR_TYPE
							&& !contextName.equalsIgnoreCase(Constants.MODULE)) {
						ruleMap.put(
								contextName + "::" + transformationRuleName,
								cost);
					} else if (typeMetric == Constants.CICLOMATIC_COMPLEXITY_TYPE
							|| typeMetric == Constants.PRINT_STATEMENT_TYPE) {
						ruleMap.put(
								contextName + "::" + transformationRuleName,
								cost);
					}
					cost = 0;
				}
				// System.out.println(">> " + line + " cost: " + cost);
				if (!getStatemenType(line).equalsIgnoreCase(Constants.NO_TYPE)) {
					if (!getStatemenType(line).equalsIgnoreCase(
							Constants.PRINTSTATEMENT)
							&& typeMetric == Constants.CICLOMATIC_COMPLEXITY_TYPE) {
						cost++;
					} else if (getStatemenType(line).equalsIgnoreCase(
							Constants.PRINTSTATEMENT)
							&& typeMetric == Constants.PRINT_STATEMENT_TYPE) {
						cost++;
					}

				}
				if (typeMetric == Constants.NMTR_TYPE) {
					if (line.contains(Constants.ITERATOR_STATEMENT)) {
						var = getVar(line);
						isVar = true;
					} else if (line.contains(Constants.BLOCKSTATEMENT) && isVar) {
						isVar = false;
						var = Constants.DEFAULT;
					}

					if (isVar) {
						if (getCostNMTR(line, var) > cost) {
							// System.out.println(var + " : " + line);
							cost = getCostNMTR(line, var);
						}
					}
					if (cost < getCostNMTR(line)) {
						cost = getCostNMTR(line);
					}
				}
			}

			allInformations.put(transformationName, ruleMap);
		}

		return allInformations;
	}

	private int verifyNMTR(List<String> list, String line) {
		if (list.isEmpty()) {
			return getCostNMTR(line);
		}
		for (String aux : list) {
			if (getCostNMTR(line) > getCostNMTR(aux)) {
				return getCostNMTR(line) - getCostNMTR(aux);
			}
		}
		return 0;
	}

	private String getTransformationRuleName(String line) {
		int initIndex = line.indexOf(Constants.NAME) + 5;
		int finalIndex = line.substring(initIndex + 1).indexOf("\"");
		if (finalIndex == -1 || initIndex == -1)
			return "";
		return line.substring(initIndex + 1).substring(0, finalIndex);

	}

	private String getVar(String line) {
		int initIndex = line.indexOf(Constants.VAR) + 9;
		int finalIndex = line.substring(initIndex + 1).indexOf("\"");
		if (finalIndex == -1 || initIndex == -1)
			return "";
		return line.substring(initIndex + 1).substring(0, finalIndex);
	}

	private String getContext(String line) {
		int initIndex = line.indexOf(Constants.INIT_TYPE) + 5;
		int finalIndex = line.substring(initIndex + 1).indexOf("\"");
		if (finalIndex == -1 || initIndex == -1)
			return "";
		return line.substring(initIndex + 1).substring(0, finalIndex);
	}

	private String getTransformationName(List<String> transformation) {
		for (String line : transformation) {
			if (!line.contains(Constants.OPEN_TAG
					+ Constants.TRANSFORMATION_RULE)
					&& line.contains(Constants.OPEN_TAG
							+ Constants.TRANSFORMATION)) {
				int initIndex = line.indexOf(Constants.NAME) + 5;
				int finalIndex = line.substring(initIndex + 1).indexOf("\"");
				return line.substring(initIndex + 1).substring(0, finalIndex);
			}
		}
		return "NOTHING";
	}

	private boolean isStatement(String line) {
		return line.replace(" ", "").startsWith(
				(Constants.OPEN_TAG + Constants.STATEMENTS));
	}

	private String getStatemenType(String statement) {

		if (statement.contains(Constants.OPEN_TAG + Constants.ELSE_BRANCH)) {
			return Constants.ELSE_BRANCH;
		} else if (isStatement(statement)) {
			if (statement.contains(Constants.IFSTATEMENT)) {
				return Constants.IFSTATEMENT;
			} else if (statement.contains(Constants.ITERATOR_STATEMENT)) {
				return Constants.ITERATOR_STATEMENT;
			} else if (statement.contains(Constants.RESULT_ASSIGNMENT)) {
				return Constants.RESULT_ASSIGNMENT;
			} else if (statement
					.contains(Constants.VARIABLE_DECLARATION_STATEMENT)) {
				return Constants.VARIABLE_DECLARATION_STATEMENT;
			} else if (statement.contains(Constants.WHILE_STATEMENT)) {
				return Constants.WHILE_STATEMENT;
			} else if (statement.contains(Constants.PRINTSTATEMENT)) {
				return Constants.PRINTSTATEMENT;
			}

		}
		return Constants.NO_TYPE;
	}

	public File[] getTransformations(String path) {
		File[] transformations = null;
		try {
			transformations = this.fileManager.getTransformationsFiles(path,
					"mofscript");
		} catch (IOException e) {
			e.printStackTrace();
		}
		return transformations;
	}

}
